/* 
 * Copyright (C) 2015 fede
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package Control;

import Entity.Calendar;
import Entity.Event;
import Entity.NotifyLink;
import Entity.NotifyReply;
import Entity.RegisteredUser;
import java.security.Principal;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;

/**
 *
 * @author fede
 */
@Stateless
public class CalendarFacade extends AbstractFacade<Calendar> {

    @PersistenceContext
    EntityManager em;

    /**
     * get entity manager
     *
     * @return entity manager of the class
     */
    @Override
    protected EntityManager getEntityManager() {
        return em;
    }

    @Inject
    Principal principal;

    @EJB
    private WeatherForecastFacade wff;

    @EJB
    private NotifyReplyFacade nrf;

    @EJB
    private NotifyLinkFacade nlf;

    @EJB
    private RegisteredUserFacade ruf;

    @EJB
    private EventFacade ef;

    /**
     * Save calendar in DB
     *
     * @param calendar to save
     */
    public void save(Calendar calendar) {
        em.persist(calendar);
    }

    /**
     * this method update the weather forecast of event if they are in 3 day to
     * current date. Next create notification for user.
     *
     * @return List of event analyzed
     */
    public List<Event> updateEventNex3DayWeatherAndNotify() {
        List<Event> temp = em.find(Calendar.class, principal.getName()).getEvent();
        for (int i = 0; i < temp.size(); i++) {
            if (temp.get(i).getStartEventDate().after(GregorianCalendar.getInstance().getTime())
                    && temp.get(i).getStartEventDate().before(nextXDay(3))
                    && temp.get(i).getIndoor_bool() == false) {
                wff.updateWeather(temp.get(i).getWeatherForecast(), temp.get(i).getLocation(), temp.get(i).getStartEventDate());
                if (temp.get(i).getWeatherForecast() != null && (temp.get(i).getWeatherForecast().getDescriptionId() < 800 || temp.get(i).getWeatherForecast().getDescriptionId() > 804)) {
                    Date d = wff.closestSunnyDay(temp.get(i).getStartEventDate(), temp.get(i).getLocation());
                    if (!d.equals(temp.get(i).getStartEventDate())) {
                        if (!nlf.hasNotify(temp.get(i), ruf.getLoggedUser())) {
                            nlf.createNotify3Day(temp.get(i), d);
                        }

                    }

                }
            }
        }
        return temp;
    }

    /**
     * this method update the weather forecast of event if they are in 1 day to
     * current date. Next create notification for user.
     *
     * @return list of event analyzed
     */
    public List<Event> updateWeatherNext1DayAndNotify() {
        List<Event> events = ef.getAllInvited();
        for (int i = 0; i < events.size(); i++) {
            if (events.get(i).getStartEventDate().before(nextXDay(1)) && events.get(i).getIndoor_bool() == false) {
                wff.updateWeather(events.get(i).getWeatherForecast(), events.get(i).getLocation(), events.get(i).getStartEventDate());
                if (events.get(i).getWeatherForecast().getDescriptionId() < 800 || events.get(i).getWeatherForecast().getDescriptionId() > 804) {
                    if (!nlf.hasNotify(events.get(i), ruf.getLoggedUser())) {
                        nlf.createNotify1Day(events.get(i));
                    }
                }
            }
        }
        return events;

    }

    /**
     * this method return the next n day of a date given
     *
     * @param x number of day to add
     * @return updated Date
     */
    public Date nextXDay(Integer x) {
        java.util.Calendar c = GregorianCalendar.getInstance();
        c.add(GregorianCalendar.DAY_OF_MONTH, +x);
        return c.getTime();

    }

    /**
     * This method add and event to calendar
     *
     * @param e Event to add
     */
    public void addEvent(Event e) {
        em.find(Calendar.class, principal.getName()).addEvent(e);
    }

    /**
     * This method delete and event to calendar
     *
     * @param e Event to delete
     */
    public void deleteEvent(Event e) {
        em.find(Calendar.class, principal.getName()).deleteEvent(e);
    }

    /**
     * This method get name and surname of current user
     *
     * @return name and surname as a string
     */
    public String getNameSurname() {
        return ruf.getNameSurname();
    }

    /**
     * Get all notifyLink for event
     *
     * @param eventId the eventId choosen
     * @return List of Notifylink
     */
    public List<NotifyLink> getAllNotifyLink(String eventId) {
        TypedQuery<NotifyLink> query = em.createNamedQuery(NotifyLink.FIND_ALL_BY_USER_AND_EVENT, NotifyLink.class);
        query.setParameter("eventId", eventId);
        query.setParameter("userX", principal.getName());
        return query.getResultList();
    }

    /**
     * Get all Notifyreply for event
     *
     * @return List of Notifyreply
     */
    public List<NotifyReply> getNotifyReply() {
        TypedQuery<NotifyReply> query = em.createNamedQuery(NotifyReply.FIND_ALL_FOR_USER, NotifyReply.class);
        query.setParameter("user", principal.getName());
        return query.getResultList();
    }

    /**
     * This methor give a list of user avialable to invite for and event
     *
     * @param toFind String to query
     * @return list of RegisteredUser
     */
    public List<RegisteredUser> getUserToInvite(String toFind) {
        TypedQuery<RegisteredUser> query = em.createNamedQuery(RegisteredUser.FIND_USER_BY_NAME_SURNAME_AND_EMAIL, RegisteredUser.class);
        query.setParameter("string", toFind + "%");
        query.setParameter("user", principal.getName());
        return query.getResultList();
    }

    /**
     * remove Notifyreply for event
     *
     * @param notifyReply to delete
     */
    public void deleteNotify(NotifyReply notifyReply) {
        nrf.remove(notifyReply);
    }

    /**
     * remove notifyLink for event
     *
     * @param notifyLink to delete
     */
    public void deleteNotifyLink(NotifyLink notifyLink) {
        nlf.remove(notifyLink);
    }

    /**
     *
     */
    public CalendarFacade() {
        super(Calendar.class);
    }

}
